/**
 * Copyright (C) 2011 the author
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.linguamathematica.oa4j;

import java.util.Set;

import static java.lang.String.format;

import com.linguamathematica.oa4j.Analysis.NER;
import com.linguamathematica.oa4j.Analysis.OfferingGuidance;
import com.linguamathematica.oa4j.Analysis.PolarityResult;
import com.linguamathematica.oa4j.Analysis.RequestingGuidance;
import com.linguamathematica.oa4j.Analysis.Result;

/**
 * The Class TopicsAnalysis.
 */
public class TopicsAnalysis
{

	/** The proper nouns. */
	private final Set<Noun> properNouns;

	/** The top topics. */
	private final Set<Noun> topTopics;

	/** The domains. */
	private final Set<Domain> domains;

	/** The locations. */
	private final Set<Result<String>> locations;

	/**
	 * Instantiates a new topics analysis.
	 * 
	 * @param properNouns
	 *            the proper nouns
	 * @param topTopics
	 *            the top topics
	 * @param domains
	 *            the domains
	 * @param locations
	 *            the locations
	 */
	protected TopicsAnalysis(final Set<Noun> properNouns, final Set<Noun> topTopics, final Set<Domain> domains,
			final Set<Result<String>> locations)
	{
		super();
		this.properNouns = properNouns;
		this.topTopics = topTopics;
		this.domains = domains;
		this.locations = locations;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj)
	{
		if (this == obj)
		{
			return true;
		}

		if (obj == null || getClass() != obj.getClass())
		{
			return false;
		}

		final TopicsAnalysis other = (TopicsAnalysis) obj;

		return domains.equals(other.domains) && locations.equals(other.locations)
				&& properNouns.equals(other.properNouns) && topTopics.equals(other.topTopics);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		final StringBuilder builder = new StringBuilder(format("Topics Analysis %n%n"));

		builder.append(format("Domains %s%n", domains.size() > 0 ? ":" : "-"));

		for (final Domain domain : domains)
		{
			builder.append(format("  %s%n", domain));
		}

		builder.append(format(" %nTop Topics %s%n", topTopics.size() > 0 ? ":" : "-"));

		for (final Noun topTopic : topTopics)
		{
			builder.append(format("  %s%n", topTopic));
		}

		builder.append(format(" %nProper Nouns %s%n", properNouns.size() > 0 ? ":" : "-"));

		for (final Noun properNoun : properNouns)
		{
			builder.append(format("  %s%n", properNoun));
		}

		builder.append(format(" %nLocations %s%n", locations.size() > 0 ? ":" : "-"));

		for (final Result<String> location : locations)
		{
			builder.append(format("  %s%n", location));
		}

		return builder.toString();
	}

	/**
	 * Gets the domains.
	 * 
	 * @return the domains
	 */
	public Set<Domain> getDomains()
	{
		return domains;
	}

	/**
	 * Gets the locations.
	 * 
	 * @return the locations
	 */
	public Set<Result<String>> getLocations()
	{
		return locations;
	}

	/**
	 * Gets the proper nouns.
	 * 
	 * @return the proper nouns
	 */
	public Set<Noun> getProperNouns()
	{
		return properNouns;
	}

	/**
	 * Gets the top topics.
	 * 
	 * @return the top topics
	 */
	public Set<Noun> getTopTopics()
	{
		return topTopics;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + domains.hashCode();
		result = prime * result + locations.hashCode();
		result = prime * result + properNouns.hashCode();
		return prime * result + topTopics.hashCode();
	}

	/**
	 * The Class Domain.
	 */
	public static class Domain
	{

		/** The sub domain. */
		private final Domain subDomain;

		/** The topic. */
		private final Result<String> topic;

		/** The NULL. */
		public static Domain NULL = new Domain()
		{
			@Override
			public boolean equals(final Object obj)
			{
				return this == obj;
			}

			@Override
			public Domain getSubDomain()
			{
				return this;
			};

			@Override
			public int hashCode()
			{
				return 0;
			}

			@Override
			public String toString()
			{
				return "";
			}
		};

		/**
		 * Instantiates a new domain.
		 * 
		 * @param topic
		 *            the topic
		 * @param subDomain
		 *            the sub domain
		 */
		public Domain(final Analysis.Result<String> topic, final Domain subDomain)
		{
			this.topic = topic;
			this.subDomain = subDomain;
		}

		/**
		 * Instantiates a new domain.
		 */
		private Domain()
		{
			topic = Result.nullResult();
			subDomain = null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(final Object obj)
		{
			if (this == obj)
			{
				return true;
			}

			if (obj == null || getClass() != obj.getClass())
			{
				return false;
			}

			final Domain other = (Domain) obj;

			return subDomain.equals(other.subDomain) && topic.equals(other.topic);
		}

		/**
		 * Gets the sub domain.
		 * 
		 * @return the sub domain
		 */
		public Domain getSubDomain()
		{
			return subDomain;
		}

		/**
		 * Gets the topic.
		 * 
		 * @return the topic
		 */
		public Result<String> getTopic()
		{
			return topic;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#hashCode()
		 */
		@Override
		public int hashCode()
		{
			final int prime = 31;
			int result = 1;
			result = prime * result + subDomain.hashCode();
			return prime * result + topic.hashCode();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString()
		{
			return format(subDomain != Domain.NULL ? "Domain %s >  %s" : "Domain %s", topic, subDomain);
		}
	}

	/**
	 * The Class Noun.
	 */
	public static class Noun
	{

		/** The topic. */
		private final Result<String> topic;

		/** The polarity. */
		private final PolarityResult polarity;

		/** The offering guidance. */
		private final Result<OfferingGuidance> offeringGuidance;

		/** The requesting guidance. */
		private final Result<RequestingGuidance> requestingGuidance;

		/** The ner. */
		private final NER ner;

		/**
		 * Instantiates a new noun.
		 * 
		 * @param result
		 *            the result
		 * @param polarity
		 *            the polarity
		 * @param offeringGuidance
		 *            the offering guidance
		 * @param requestingGuidance
		 *            the requesting guidance
		 * @param ner
		 *            the ner
		 */
		public Noun(final Result<String> result, final PolarityResult polarity,
				final Result<OfferingGuidance> offeringGuidance, final Result<RequestingGuidance> requestingGuidance,
				final NER ner)
		{
			topic = result;
			this.polarity = polarity;
			this.offeringGuidance = offeringGuidance;
			this.requestingGuidance = requestingGuidance;
			this.ner = ner;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(final Object obj)
		{
			if (this == obj)
			{
				return true;
			}

			if (obj == null || getClass() != obj.getClass())
			{
				return false;
			}

			final Noun other = (Noun) obj;

			return ner.equals(other.ner) && offeringGuidance.equals(other.offeringGuidance)
					&& polarity.equals(other.polarity) && requestingGuidance.equals(other.requestingGuidance)
					&& topic.equals(other.topic);
		}

		/**
		 * Gets the ner.
		 * 
		 * @return the ner
		 */
		public NER getNer()
		{
			return ner;
		}

		/**
		 * Gets the offering guidance.
		 * 
		 * @return the offering guidance
		 */
		public Result<OfferingGuidance> getOfferingGuidance()
		{
			return offeringGuidance;
		}

		/**
		 * Gets the polarity.
		 * 
		 * @return the polarity
		 */
		public PolarityResult getPolarity()
		{
			return polarity;
		}

		/**
		 * Gets the requesting guidance.
		 * 
		 * @return the requesting guidance
		 */
		public Result<RequestingGuidance> getRequestingGuidance()
		{
			return requestingGuidance;
		}

		/**
		 * Gets the topic.
		 * 
		 * @return the topic
		 */
		public Result<String> getTopic()
		{
			return topic;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#hashCode()
		 */
		@Override
		public int hashCode()
		{
			final int prime = 31;
			int theResult = 1;
			theResult = prime * theResult + ner.hashCode();
			theResult = prime * theResult + offeringGuidance.hashCode();
			theResult = prime * theResult + polarity.hashCode();
			theResult = prime * theResult + requestingGuidance.hashCode();
			return prime * theResult + topic.hashCode();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString()
		{
			return format("Noun%n   topic %s%n   polarity %s%n   offeringGuidance %s%n   requestingGuidance %s"
					+ (ner == NER.NULL ? "" : "%n   NER %s"), topic, polarity, offeringGuidance, requestingGuidance,
					ner);
		}
	}
}
